import { Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpErrorResponse,
  HttpSentEvent,
  HttpHeaderResponse,
  HttpProgressEvent,
  HttpResponse,
  HttpUserEvent, HttpEvent,
} from '@angular/common/http';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { mergeMap, catchError, switchMap, take, filter, debounceTime } from 'rxjs/operators';

import { HttpService } from '@core';
import { environment } from '@env/environment';
import { ApesMessageService } from '@shared/apes/message';
import { UserAuthService } from '@core/services/user-auth.service';
import { ApesLoginComponent } from '@shared/apes-login';
import { ApiService } from '@core/services/http/api.service';

/**
 * 默认HTTP拦截器，其注册细节见 `app.module.ts`
 */
@Injectable()
export class DefaultInterceptor implements HttpInterceptor {

  isLogin: boolean = false;
  tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);

  requestSessionSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  constructor(private injector: Injector, private loginService: ApesLoginComponent,
              private userAuthService: UserAuthService, private api: ApiService) {
    this.tokenSubject.subscribe(value => {
      console.log(value);
    });

    // 监听重新获取seesionId
    this.requestSessionSubject.pipe(debounceTime(500))
      .subscribe(() => {
        let userInfoModel = this.userAuthService.getUserInfoObj();
        if (userInfoModel.userAccount && userInfoModel.userAccount.userId) {
          const hash = this.userAuthService.getUserHash(userInfoModel.userAccount.userId);
          this.api.post('aut.user.loginIgnorePassword', {
            userId: userInfoModel.userAccount.userId,
            post: userInfoModel.userAccount.post,
            accessKey: userInfoModel.userAccount.accessKey,
            terminal: userInfoModel.terminal,
            hash: hash
          }).pipe(debounceTime(100)).subscribe((body) => {
            if (body) {
              userInfoModel.token = body.sessionId;
              this.userAuthService.storeUserInfo(JSON.stringify(userInfoModel));
              this.tokenSubject.next(body.sessionId);
            }
          });
        } else {
          this.msg.error('用户信息缺失，请退出重新登录！'); // 该用户已禁用，请联系行政人员
        }
      });
  }

  get msg(): ApesMessageService {
    return this.injector.get(ApesMessageService);
  }

  private goTo(url: string) {
    setTimeout(() => this.injector.get(Router).navigateByUrl(url));
  }

  private handleData(
    event: HttpResponse<any> | HttpErrorResponse, req: HttpRequest<any>, next: HttpHandler,
  ): Observable<any> {
    // 可能会因为 `throw` 导出无法执行 `_HttpClient` 的 `end()` 操作
    this.injector.get(HttpService).end();
    // 业务处理：一些通用操作
    switch (event.status) {
      case 200:
        // 业务层级错误处理，以下是假定restful有一套统一输出格式（指不管成功与否都有相应的数据格式）情况下进行处理
        // 例如响应内容：
        //  错误内容：{ status: 1, msg: '非法参数' }
        //  正确内容：{ status: 0, response: {  } }
        // 则以下代码片断可直接适用
        if (event instanceof HttpResponse) {
          const body: any = event.body;
          if (body.hasOwnProperty('header') && body.header.code == 'invalid_session') {
            const userInfo = this.userAuthService.getUserInfoObj();
            if (userInfo) {
              return this.handle401Error(req, next, body);
            }
          }
        }
        break;
      case 401: // 未登录状态码
        this.goTo('/passport/login');
        break;
      case 403:
      case 404:
        this.msg.error('系统异常，请稍后重试！');
        break;
      case 500:
        let message;
        if (event instanceof HttpErrorResponse) {
          message = event.error['message'];
        } else {
          message = event['message'];
        }
        this.msg.error(message);
        throw new Error(message);
        // this.goTo(`/${event.status}`);
        break;
      case 504:
        this.msg.error('系统超时，请重试！');
        break;
      default:
        if (event instanceof HttpErrorResponse) {
          console.warn(
            '未可知错误，大部分是由于后端不支持CORS或无效配置引起',
            event,
          );
          // this.msg.error(event.message);
          console.error(event);
          throw new Error(event.message);
        }
        break;
    }
    return of(event);
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<| HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    // 统一加上服务端前缀
    let url = req.url;
    if (!url.startsWith('https://') && !url.startsWith('http://')) {
      url = environment.SERVER_URL + url;
    }

    const newReq = req.clone({
      url: url,
    });
    return next.handle(newReq).pipe(
      mergeMap((event: any) => {
        // 允许统一对请求错误处理，这是因为一个请求若是业务上错误的情况下其HTTP请求的状态是200的情况下需要
        if (event instanceof HttpResponse && event.status === 200)
          return this.handleData(event, req, next);
        // 若一切都正常，则后续操作
        return of(event);
      }),
      catchError((err: HttpErrorResponse) => this.handleData(err, req, next)),
    );
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler, body ?): Observable<HttpEvent<any>> {
    this.requestSessionSubject.next({});

    return this.tokenSubject.pipe(
      filter(token => token !== null),
      take(1),
      switchMap(sessionId => {
        request['sessionId'] = sessionId;
        return next.handle(this.reRequest(request, sessionId));
      }),
    );
  }

  /**
   *
   *
   * @private
   * @param {HttpRequest<any>} request
   * @returns {HttpRequest<any>}
   * @memberof DefaultInterceptor
   */
  private reRequest(request: HttpRequest<any>, sessionId): HttpRequest<any> {
    let newRequest = request.clone();
    newRequest.body.sessionId = sessionId;
    delete newRequest.body.sign;
    newRequest.body.sign = this.api.sign(newRequest.body);
    return newRequest;
  }


}
